package com.qingfeng.medical.job.hosp;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.qingfeng.medical.base.utils.DateWeek;
import com.qingfeng.medical.biz.hosp.domain.entity.HospDepartment;
import com.qingfeng.medical.biz.hosp.domain.entity.Schedule;
import com.qingfeng.medical.biz.hosp.service.HospDepartmentService;
import com.qingfeng.medical.biz.hosp.service.ScheduleService;
import com.qingfeng.medical.biz.information.domain.entity.DoctorInfo;
import com.qingfeng.medical.biz.information.service.DoctorInfoService;
import com.qingfeng.medical.biz.information.service.HospitalInfoService;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 指定每天24:00生成预约周期后一天的预约挂号信息
 *
 * @author 清风学Java
 * @version 1.0.0
 * @date 2023/4/14
 */
@Component
@Slf4j
public class ScheduleTimedGenerationHandler {

    @Autowired
    private HospitalInfoService hospitalInfoService;
    @Autowired
    private HospDepartmentService hospDepartmentService;
    @Autowired
    private DoctorInfoService doctorInfoService;
    @Autowired
    private ScheduleService scheduleService;

    /**
     * 指定每天24:00生成预约周期后一天的预约挂号信息
     * <p>
     * 如果有生成失败的，要记录信息，通知手动添加
     *
     * @return
     */
    @XxlJob(value = "TimedGenerationHandler")
    public ReturnT timedGeneration() {
        // 查询预约周期  根据预约周期推算时间
        Integer cycle = hospitalInfoService.list()
                .get(0)
                .getBookingRule()
                .getCycle();

        // 计算时间
        LocalDate localDate = LocalDate.now().plusDays(10);
        // 获取该日期是星期几
        String weekDay = DateWeek.dateToWeek(localDate);
        // 查询该工作日下的医生
        List<DoctorInfo> doctorInfoList = doctorInfoService.list(
                new LambdaQueryWrapper<DoctorInfo>()
                        .like(DoctorInfo::getWeekday, "%" + weekDay + "%")
        );

        if (CollUtil.isEmpty(doctorInfoList)) {
            return ReturnT.SUCCESS;
        }

        List<DoctorInfo> collect = doctorInfoList.stream()
                .filter(d -> CollUtil.isNotEmpty(d.getDepartmentPatient()))
                .collect(Collectors.toList());

        if (CollUtil.isEmpty(collect)) {
            return ReturnT.SUCCESS;
        }

        List<Long> depIds = collect.stream()
                .map(d ->
                        d.getDepartmentPatient()
                                .stream()
                                .flatMap(Collection::stream)
                                .filter(id -> id != 0)
                                .collect(Collectors.toSet())
                )
                .flatMap(Collection::stream)
                .collect(Collectors.toList());
        // 根据Ids查询科室门诊信息，封装Map
        Map<Long, HospDepartment> hospDepartmentMap = hospDepartmentService.list(
                        new LambdaQueryWrapper<HospDepartment>()
                                .in(HospDepartment::getId, depIds)
                )
                .stream()
                .collect(Collectors.toMap(
                        HospDepartment::getId,
                        Function.identity()
                ));

        // 根据医生所属科室-门诊生成预约信息
        collect.forEach(d -> {
                    try {
                        d.getDepartmentPatient()
                                .stream()
                                .flatMap(Collection::stream)
                                .filter(id -> id != 0)
                                .forEach(depId -> {
                                    // 生成预约信息
                                    try {
                                        scheduleService.save(Schedule.builder()
                                                .doctorId(d.getUserId())
                                                .depId(depId)
                                                .workDate(Date.from(
                                                                localDate.atStartOfDay()
                                                                        .atZone(ZoneId.systemDefault())
                                                                        .toInstant()
                                                        )
                                                )
                                                .signalSource(100)
                                                .reservationNum(0)
                                                .availableNum(100)
                                                .status(1)
                                                .price(d.getPosition().getPrice())
                                                .build());
                                    } catch (Exception e) {
                                        e.printStackTrace();
                                        log.error("预约信息生成失败（科室-门诊）——{}", hospDepartmentMap.get(depId));
                                    }
                                });
                    } catch (Exception e) {
                        // TODO 等消息管理完善后补充消息通知
                        e.printStackTrace();
                        log.error("预约信息生成医师信息错误-{}", d);
                    }
                }
        );

        return ReturnT.SUCCESS;
    }

    /**
     * 将已过期的排版状态修改——每天晚上两点执行
     *
     * @return
     */
    @XxlJob(value = "TimedOutModificationStatus")
    public ReturnT timedOutModificationStatus() {
        List<Schedule> scheduleList = scheduleService.list(
                new LambdaQueryWrapper<Schedule>()
                        .lt(Schedule::getWorkDate, Date.from(
                                LocalDate.now().atStartOfDay()
                                        .atZone(ZoneId.systemDefault())
                                        .toInstant()
                        ))
                        .eq(Schedule::getStatus, 1)
        );

        if (CollUtil.isNotEmpty(scheduleList)) {
            scheduleService.updateBatchById(
                    scheduleList.stream()
                            .map(s -> s.setStatus(0))
                            .collect(Collectors.toList())
            );

        }

        return ReturnT.SUCCESS;
    }

}
